package com.kyivmohyla.kma2.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;
import com.google.inject.Inject;
import com.kyivmohyla.kma2.client.events.*;
import com.kyivmohyla.kma2.client.events.engineer.*;
import com.kyivmohyla.kma2.client.events.manager.*;
import com.kyivmohyla.kma2.client.events.operator.*;
import com.kyivmohyla.kma2.client.events.refbook.*;
import com.kyivmohyla.kma2.client.gin.Injector;
import com.kyivmohyla.kma2.client.presenter.LoginAllowViewPresenter;
import com.kyivmohyla.kma2.client.presenter.LoginDeniedViewPresenter;
import com.kyivmohyla.kma2.client.presenter.LoginViewPresenter;
import com.kyivmohyla.kma2.client.presenter.Presenter;
import com.kyivmohyla.kma2.client.presenter.engineer.EngineerEditOrderPresenter;
import com.kyivmohyla.kma2.client.presenter.engineer.EngineerMainViewPresenter;
import com.kyivmohyla.kma2.client.presenter.header.HeaderPresenter;
import com.kyivmohyla.kma2.client.presenter.manager.ManagerEditOrderPresenter;
import com.kyivmohyla.kma2.client.presenter.manager.ManagerMainViewPresenter;
import com.kyivmohyla.kma2.client.presenter.manager.ManagerOpenClosedOrdersPresenter;
import com.kyivmohyla.kma2.client.presenter.operator.OperatorEditOrderPresenter;
import com.kyivmohyla.kma2.client.presenter.operator.OperatorMainViewPresenter;
import com.kyivmohyla.kma2.client.presenter.refbook.NewItemTreeGridViewPresenter;
import com.kyivmohyla.kma2.client.presenter.refbook.TreeGridViewPresenter;
import com.kyivmohyla.kma2.client.utils.Dialog;
import com.kyivmohyla.kma2.client.utils.ExportOrder;
import com.kyivmohyla.kma2.client.utils.OrdersExport;
import com.kyivmohyla.kma2.shared.model.UIImportOrder;
import com.kyivmohyla.kma2.shared.model.UIOrder;
import com.kyivmohyla.kma2.shared.model.UIStaff;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class AppController implements Presenter, ValueChangeHandler<String> {

    private HasWidgets container;
    private UIStaff currentStaff;
    private Object parameter;

    @Inject
    public AppController() {
        bind();
    }

    private void bind() {
        History.addValueChangeHandler(this);
        final Injector injector = Injector.INSTANCE;
        injector.getEventBus().addHandler(LoginEvent.TYPE,
                new LoginEventHandler() {
                    @Override
                    public void onLogin(LoginEvent event) {
                        doLogin();
                    }
                });
        injector.getEventBus().addHandler(LogoutEvent.TYPE,
                new LogoutEventHandler() {
                    @Override
                    public void onLogout(LogoutEvent event) {
                        doLogout();
                    }
                });

        injector.getEventBus().addHandler(LoginAllowEvent.TYPE,
                new LoginAllowEventHandler() {
                    @Override
                    public void onLoginAllow(LoginAllowEvent event) {
                        doLoginAllow(event.getLoginStaff());
                    }
                });
        injector.getEventBus().addHandler(LoginDeniedEvent.TYPE,
                new LoginDeniedEventHandler() {
                    @Override
                    public void onLoginDenied(LoginDeniedEvent event) {
                        doLoginDenied();
                    }
                });

        injector.getEventBus().addHandler(OperatorLoginEvent.TYPE,
                new OperatorLoginEventHandler() {
                    @Override
                    public void onOperatorLogin(OperatorLoginEvent event) {
                        doOperatorLogin(event.getOperatorStaff());
                    }
                });
        injector.getEventBus().addHandler(ManagerLoginEvent.TYPE,
                new ManagerLoginEventHandler() {
                    @Override
                    public void onManagerLogin(ManagerLoginEvent event) {
                        doManagerLogin(event.getManagerStaff());
                    }
                });
        injector.getEventBus().addHandler(EngineerLoginEvent.TYPE,
                new EngineerLoginEventHandler() {
                    @Override
                    public void onEngineerLogin(EngineerLoginEvent event) {
                        doEngineerLogin(event.getEngineerStaff());
                    }
                });

        injector.getEventBus().addHandler(OperatorEditOrderEvent.TYPE,
                new OperatorEditOrderEventHandler() {
                    @Override
                    public void onOperatorEditOrderWindow(OperatorEditOrderEvent event) {
                        doOperatorEditOrder(event.getSelectedOrder());
                    }
                });
        injector.getEventBus().addHandler(ManagerEditOrderEvent.TYPE,
                new ManagerEditOrderEventHandler() {
                    @Override
                    public void onManagerEditOrder(ManagerEditOrderEvent event) {
                        doManagerEditOrder(event.getSelectedOrder());
                    }
                });

        injector.getEventBus().addHandler(TreeGridOpenEvent.TYPE,
                new TreeGridOpenEventHandler() {
                    @Override
                    public void onTreeGridOpen(TreeGridOpenEvent event) {
                        doOpenTreeGrid(event.getType());
                    }
                });
        injector.getEventBus().addHandler(OpenWindowToAddObjectToRefBookEvent.TYPE,
                new OpenWindowToAddObjectToRefBookEventHandler() {
                    @Override
                    public void onAddItemTreeGrid(OpenWindowToAddObjectToRefBookEvent event) {
                        doOpenAddItemTreeGrid(event.getType());
                    }
                });
        injector.getEventBus().addHandler(AddObjectToReferenceBookEvent.TYPE,
                new AddObjectToReferenceBookEventHandler() {
                    @Override
                    public void onAddObjectToReferenceBook(AddObjectToReferenceBookEvent event) {
                        doOpenTreeGrid(event.getType());
                    }
                });

        injector.getEventBus().addHandler(OperatorNewOrderEvent.TYPE,
                new OperatorNewOrderEventHandler() {
                    @Override
                    public void onOperatorNewOrder(OperatorNewOrderEvent event) {
                        doOperatorNewOrder();
                    }
                });
        injector.getEventBus().addHandler(OperatorImportEvent.TYPE,
                new OperatorImportEventHandler() {
                    @Override
                    public void onOperatorImport(OperatorImportEvent event) {
                        doImport(event.getImportOrder());
                    }
                });
        injector.getEventBus().addHandler(OperatorCloseOrderEvent.TYPE,
                new OperatorCloseOrderEventHandler() {
                    @Override
                    public void onOperatorCloseOrder(OperatorCloseOrderEvent event) {
                        doOperatorCloseOrder();
                    }
                });
        injector.getEventBus().addHandler(ManagerCloseOrderEvent.TYPE,
                new ManagerCloseOrderEventHandler() {
                    @Override
                    public void onManagerCloseOrder(ManagerCloseOrderEvent event) {
                        doManagerCloseOrder(event.getDate());
                    }
                });
        injector.getEventBus().addHandler(EngineerEditOrderEvent.TYPE,
                new EngineerEditOrderEventHandler() {
                    @Override
                    public void onEngineerEditOrder(EngineerEditOrderEvent event) {
                        doEngineerEditOrder(event.getSelectedOrder());
                    }
                });
        injector.getEventBus().addHandler(EngineerCloseOrderEvent.TYPE,
                new EngineerCloseOrderEventHandler() {
                    @Override
                    public void onEngineerCloseOrder(EngineerCloseOrderEvent event) {
                        doEngineerCloseOrder(event.getDate());
                    }
                });
        injector.getEventBus().addHandler(OrderExportEvent.TYPE,
                new OrderExportEventHandler() {
                    @Override
                    public void onOrderExport(OrderExportEvent event) {
                        doExport(event.getExportOrders());
                    }
                });
        injector.getEventBus().addHandler(ManagerClosedOrdersOpenEvent.TYPE,
                new ManagerClosedOrdersOpenEventHandler() {
                    @Override
                    public void onManagerClosedOrdersOpen(ManagerClosedOrdersOpenEvent event) {
                        doOpenClosedOrders();
                    }
                });
    }

    private void doExport(List<ExportOrder> exportOrders) {
        if (exportOrders != null && exportOrders.size() > 0) {
            FormPanel formPanel = OrdersExport.getInstance().go(exportOrders);
            FocusPanel focusPanel = new FocusPanel();
            focusPanel.add(formPanel);
            List<HasClickHandlers> list = new ArrayList<HasClickHandlers>();
            list.add(focusPanel);
            list.add(new Button("Close"));
            final DialogBox dialogBox = new DialogBox();
            dialogBox.addStyleName("gwt-DialogBox");
            dialogBox.setText("Export");
            VerticalPanel dialogContents = new VerticalPanel();
            dialogContents.addStyleName("dialogContents");
            dialogContents.setSpacing(4);
            dialogBox.setWidget(dialogContents);
            HTML text = new HTML("Are you sure, you want to export?");
            dialogContents.add(text);
            HorizontalPanel buttonPanel = new HorizontalPanel();
            buttonPanel.setSpacing(5);
            dialogContents.add(buttonPanel);
            for (HasClickHandlers button : list) {
                button.addClickHandler(new ClickHandler() {
                    @Override
                    public void onClick(ClickEvent clickEvent) {
                        dialogBox.hide();
                    }
                });
                buttonPanel.add((Widget) button);
            }
            dialogBox.setGlassEnabled(true);
            dialogBox.setAnimationEnabled(true);
            dialogBox.center();
            dialogBox.getElement().getStyle().setZIndex(1000000);
            dialogBox.show();
        }
    }

    private void doManagerCloseOrder(Date date) {
        parameter = date;
        History.newItem("managerLoggedInDate");
    }

    private void doManagerEditOrder(UIOrder selectedOrder) {
        parameter = selectedOrder;
        History.newItem("managerEditOrder");
    }

    private void doEngineerEditOrder(UIOrder selectedOrder) {
        parameter = selectedOrder;
        History.newItem("engineerEditOrder");
    }

    private void doOperatorCloseOrder() {
        History.newItem("operatorLoggedIn");
    }

    private void doEngineerCloseOrder(Date date) {
        parameter = date;
        History.newItem("engineerLoggedInDate");
    }

    private void doOperatorNewOrder() {
        History.newItem("operatorNewOrder");
    }

    private void doOpenClosedOrders() {
        History.newItem("closedOrders");
    }

    private void doOperatorEditOrder(UIOrder order) {
        parameter = order;
        History.newItem("operatorEditOrder");
    }

    private void doImport(UIImportOrder importOrder) {
        parameter = importOrder;
        History.newItem("import");
    }

    private void doLogin() {
        RootPanel.get("header").clear();
        History.newItem("login");
    }

    private void doLogout() {
        History.newItem("login");
    }

    private void doLoginAllow(UIStaff loginStaff) {
        History.newItem("allow", false);
        Presenter presenter = new LoginAllowViewPresenter(loginStaff);
        presenter.go(container);
    }

    private void doLoginDenied() {
        History.newItem("denied", false);
        Presenter presenter = new LoginDeniedViewPresenter();
        presenter.go(container);
    }

    private void doOperatorLogin(UIStaff operatorStaff) {
        this.currentStaff = operatorStaff;
        History.newItem("operatorLoggedIn");
    }

    private void doManagerLogin(UIStaff managerStaff) {
        this.currentStaff = managerStaff;
        History.newItem("managerLoggedIn");
    }

    private void doEngineerLogin(UIStaff engineerStaff) {
        this.currentStaff = engineerStaff;
        History.newItem("engineerLoggedIn");
    }

    private void doOpenTreeGrid(String type) {
        parameter = type;
        History.newItem("treeGridOpenedIn");
    }

    private void doOpenAddItemTreeGrid(String type) {
        parameter = type;
        History.newItem("OpenAddItemToTreeGridIn");
    }

    @Override
    public void go(HasWidgets container) {
        this.container = container;
        if (History.getToken().equals("")) {
            History.newItem("login");
        } else {
            History.fireCurrentHistoryState();
        }
    }

    private void doOnValueChange(String token) {
        if (token != null) {
            if (token.equals("login")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null) {
                            container.clear();
                            new LoginViewPresenter().go(container);
                        }
                    }
                });
            } else if (token.equals("allow")) {
                GWT.runAsync(new RunAsyncCallback() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess() {
                        new LoginAllowViewPresenter().go(container);
                    }
                });
            } else if (token.equals("denied")) {
                GWT.runAsync(new RunAsyncCallback() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess() {
                        new LoginDeniedViewPresenter().go(container);
                    }
                });
            } else if (token.equals("operatorLoggedIn")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null || staff.getPositionId() != 1) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new OperatorMainViewPresenter(staff).go(container);
                        }
                    }
                });
            } else if (token.equals("managerLoggedIn")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null || staff.getPositionId() != 2) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new ManagerMainViewPresenter(staff).go(container);
                        }
                    }
                });
            } else if (token.equals("managerLoggedInDate")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null || staff.getPositionId() != 2) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new ManagerMainViewPresenter(staff, (Date) parameter).go(container);
                        }
                    }
                });
            } else if (token.equals("engineerLoggedIn")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null || staff.getPositionId() != 3) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new EngineerMainViewPresenter(staff).go(container);
                        }
                    }
                });
            } else if (token.equals("engineerLoggedInDate")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null || staff.getPositionId() != 3) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new EngineerMainViewPresenter(staff, (Date) parameter).go(container);
                        }
                    }
                });
            } else if (token.equals("operatorNewOrder")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null || staff.getPositionId() != 1) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new OperatorEditOrderPresenter().go(container);
                        }
                    }
                });
            } else if (token.equals("operatorEditOrder")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null || staff.getPositionId() != 1) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            if (parameter != null) {
                                new OperatorEditOrderPresenter((UIOrder) parameter).go(container);
                            } else {
                                new OperatorEditOrderPresenter().go(container);
                            }
                        }
                    }
                });
            } else if (token.equals("managerEditOrder")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null || staff.getPositionId() != 2) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new ManagerEditOrderPresenter((UIOrder) parameter).go(container);
                        }
                    }
                });
            } else if (token.equals("engineerEditOrder")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null || staff.getPositionId() != 3) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new EngineerEditOrderPresenter((UIOrder) parameter).go(container);
                        }
                    }
                });
            } else if (token.equals("treeGridOpenedIn")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new TreeGridViewPresenter((String) parameter, staff).go(container);
                        }
                    }
                });
            } else if (token.equals("OpenAddItemToTreeGridIn")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new NewItemTreeGridViewPresenter((String) parameter).go(container);
                        }
                    }
                });
            } else if (token.equals("import")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            if (parameter != null) {
                                new OperatorEditOrderPresenter((UIImportOrder) parameter).go(container);
                            } else {
                                new OperatorEditOrderPresenter().go(container);
                            }
                        }
                    }
                });
            } else if (token.equals("closedOrders")) {
                LoginService.App.getInstance().checkLogin(new AsyncCallback<UIStaff>() {
                    @Override
                    public void onFailure(Throwable throwable) {
                        Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                    }

                    @Override
                    public void onSuccess(UIStaff staff) {
                        if (staff == null) {
                            History.newItem("login");
                        } else {
                            new HeaderPresenter(staff).go(RootPanel.get("header"));
                            new ManagerOpenClosedOrdersPresenter().go(container);
                        }
                    }
                });
            }
        }
    }

    @Override
    public void onValueChange(ValueChangeEvent<String> stringValueChangeEvent) {
        final String token = stringValueChangeEvent.getValue();
        if (this.currentStaff != null) {
            LoginService.App.getInstance().login(this.currentStaff, new AsyncCallback<Void>() {
                @Override
                public void onFailure(Throwable throwable) {
                    Dialog.getInstance().createDialogBoxWithMessage("Error", throwable.getMessage());
                }

                @Override
                public void onSuccess(Void aVoid) {
                    doOnValueChange(token);
                    AppController.this.currentStaff = null;
                }
            });
        } else {
            doOnValueChange(token);
        }
    }
}
